package yyy.ab.common.enums.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import yyy.ab.common.core.BaseEnum;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

//@MappedJdbcTypes(JdbcType.CHAR)     //数据库类型
//@MappedTypes({BaseEnum.class})      //java数据类型
public class BaseEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

    private Class<E> type;

    private Class valueClazz;

    public BaseEnumTypeHandler() {
    }

    public BaseEnumTypeHandler(Class<E> type) {
        this.type = type;
        try {
            Field valueField = type.getDeclaredField("value");
            valueClazz = valueField.getType();
        } catch (NoSuchFieldException e) {
            valueClazz = String.class;
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, E e, JdbcType jdbcType) throws SQLException {
        Object eValue = getEValue(e);
        if (valueClazz == int.class) {
            preparedStatement.setInt(i, eValue == null ? 0 : (int) eValue);
        } else if (valueClazz == short.class) {
            preparedStatement.setShort(i, eValue == null ? 0 : (short) eValue);
        } else if (valueClazz == String.class) {
            preparedStatement.setString(i, eValue == null ? "" : eValue.toString());
        } else {
            preparedStatement.setObject(i, eValue);
        }

    }

    @Override
    public E getNullableResult(ResultSet resultSet, String s) throws SQLException {
        Object object = resultSet.getObject(s);
        return get(object);
    }

    @Override
    public E getNullableResult(ResultSet resultSet, int i) throws SQLException {
        Object object = resultSet.getObject(i);
        return get(object);
    }

    @Override
    public E getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        Object object = callableStatement.getObject(i);
        return get(object);
    }

    /**
     * 获取Enum值
     *
     * @param e Enum对象
     * @return 值
     */
    private Object getEValue(E e) {
        Method method;
        Object result = null;
        try {
            method = type.getMethod("getValue");
            result = method.invoke(e);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
            ex.printStackTrace();
        }
        return result;
    }

    /**
     * 获取数据库值对应的Enum
     *
     * @param v 数据库值
     * @return Enum对象
     */
    private E get(Object v) {
        if (v == null) return null;
        return get(type, v);
    }

    @SuppressWarnings("unchecked")
    private E get(Class<E> type, Object v) {
        Method method;
        E result = null;
        try {
            method = type.getMethod("get", valueClazz);
            if (valueClazz == short.class) {
                short val = Short.valueOf(v.toString());
                result = (E) method.invoke(type, val);
            } else if (valueClazz == int.class) {
                int val = Integer.valueOf(v.toString());
                result = (E) method.invoke(type, val);
            } else {
                result = (E) method.invoke(type, v.toString());
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }
}

